package me.kaede.tagview;

import me.kaede.tagview.util.AttrUtil;
import me.kaede.tagview.util.LogUtil;
import me.kaede.tagview.util.MyUtils;
import me.kaede.tagview.util.NumberUtil;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentState;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * TagView
 *
 * @since 2021-06-07
 */
public class TagView extends DependentLayout implements ComponentContainer.EstimateSizeListener {
    /**
     * TAG
     */
    public static final String TAG = "TagView";
    private Context mContext;
    private int mWidth;
    private int lineMargin;
    private int tagMargin;
    private int textPaddingLeft;
    private int textPaddingRight;
    private int textPaddingTop;
    private int texPaddingBottom;
    private List<Tag> mTags = new ArrayList<>();
    private OnTagClickListener mClickListener;
    private OnTagDeleteListener mDeleteListener;

    /**
     * TagView
     *
     * @param context
     */
    public TagView(Context context) {
        super(context, null);
        LogUtil.error(TAG, "[TagView]constructor 1");
        init(context, null, null);
    }

    /**
     * TagView
     *
     * @param context
     * @param attrs
     */
    public TagView(Context context, AttrSet attrs) {
        super(context, attrs);
        LogUtil.error(TAG, "[TagView]constructor 2");
        init(context, attrs, null);
    }

    /**
     * TagView
     *
     * @param ctx
     * @param attrs
     * @param defStyle
     */
    public TagView(Context ctx, AttrSet attrs, String defStyle) {
        super(ctx, attrs, defStyle);
        LogUtil.error(TAG, "[TagView]constructor 3");
        init(ctx, attrs, defStyle);
    }

    /**
     * init
     *
     * @param context
     * @param attr
     * @param defStyleRes
     */
    private void init(Context context, AttrSet attr, String defStyleRes) {
        LogUtil.error(TAG, "[init]");
        this.mContext = context;
        // get AttributeSet
        this.lineMargin = AttrUtil.getDimension(attr, "lineMargin", ResolutionUtil.dpToPx(this.getContext(), Constants.DEFAULT_LINE_MARGIN));
        this.tagMargin = AttrUtil.getDimension(attr, "tagMargin", ResolutionUtil.dpToPx(this.getContext(), Constants.DEFAULT_TAG_MARGIN));
        this.textPaddingLeft = AttrUtil.getDimension(attr, "textPaddingLeft", ResolutionUtil.dpToPx(this.getContext(), Constants.DEFAULT_TAG_TEXT_PADDING_LEFT));

        this.textPaddingRight = AttrUtil.getDimension(attr, "textPaddingRight", ResolutionUtil.dpToPx(this.getContext(), Constants.DEFAULT_TAG_TEXT_PADDING_RIGHT));
        this.textPaddingTop = AttrUtil.getDimension(attr, "textPaddingTop", ResolutionUtil.dpToPx(this.getContext(), Constants.DEFAULT_TAG_TEXT_PADDING_TOP));
        this.texPaddingBottom = AttrUtil.getDimension(attr, "textPaddingBottom", ResolutionUtil.dpToPx(this.getContext(), Constants.DEFAULT_TAG_TEXT_PADDING_BOTTOM));
        mWidth = ResolutionUtil.getScreenWidth(context);
    }

    /**
     * onEstimateSize
     *
     * @param widthEstimatedConfig
     * @param heightEstimatedConfig
     * @return boolean
     */
    @Override
    public boolean onEstimateSize(int widthEstimatedConfig, int heightEstimatedConfig) {
        mWidth = widthEstimatedConfig;
        return false;
    }

    /**
     * drawTags
     */
    private void drawTags() {
        LogUtil.error(TAG, "[drawTags]visibility = " + (getVisibility() == VISIBLE));
        if (getVisibility() != VISIBLE) return;
        LogUtil.error(TAG, "[drawTags]mWidth = " + mWidth);
        LogUtil.error(TAG, "[drawTags]add tags, tag count = " + mTags.size());
        // clear all tag
        removeAllComponents();
        // layout padding left & layout padding right
        float total = getPaddingLeft() + getPaddingRight();
        int listIndex = 1;// List Index
        int index_bottom = 1;// The Tag to add below
        int index_header = 1;// The header tag of this line
        Tag tag_pre = null;
        for (Tag item : mTags) {
            final int position = listIndex - 1;
            final Tag tag = item;
            // inflate tag layout
            Component tagLayout = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_tagview_item, null, false);
            tagLayout.setId(listIndex);
            //设置点击背景颜色
            tagLayout.setBackground(getSelector(tag));
            // tag text
            Text tagView = (Text) tagLayout.findComponentById(ResourceTable.Id_tv_tag_item_contain);
            tagView.setText(tag.text);
            //tagView.setPadding(textPaddingLeft, textPaddingTop, textPaddingRight, texPaddingBottom);
            DirectionalLayout.LayoutConfig params = (DirectionalLayout.LayoutConfig) tagView.getLayoutConfig();

            LogUtil.error("textPaddingLeft", textPaddingLeft + "");

            params.setMargins(textPaddingLeft, textPaddingTop, textPaddingRight, texPaddingBottom);
            tagView.setLayoutConfig(params);
            tagView.setTextColor(new Color(tag.tagTextColor));
            tagView.setTextSize((int) tag.tagTextSize, Text.TextSizeType.FP);
            tagLayout.setClickedListener(view -> {
                if (mClickListener != null) {
                    mClickListener.onTagClick(position, tag);
                }
            });

            // calculate　of tag layout width

            Paint text1Paint = new Paint();
            text1Paint.setTextSize(tagView.getTextSize());
            float text1Width = text1Paint.measureText(tag.text);
            int textPadding = textPaddingLeft + textPaddingRight;

            float tagWidth = (float) NumberUtil.add(text1Width,textPadding);
            // tagView padding (left & right)
            // deletable text
            Text deletableView = (Text) tagLayout.findComponentById(ResourceTable.Id_tv_tag_item_delete);
            if (tag.isDeletable) {
                deletableView.setVisibility(VISIBLE);
                deletableView.setText(tag.deleteIcon);
                int offset = ResolutionUtil.dpToPx(getContext(), 2f);
                deletableView.setPadding(offset, textPaddingTop, textPaddingRight + offset, texPaddingBottom);
                /*params = (LinearLayout.LayoutParams) deletableView.getLayoutParams();
				params.setMargins(offset, textPaddingTop, textPaddingRight+offset, texPaddingBottom);
				deletableView.setLayoutParams(params);*/
                deletableView.setTextColor(new Color(tag.deleteIndicatorColor));

                deletableView.setTextSize((int) tag.deleteIndicatorSize, Text.TextSizeType.FP);
                deletableView.setClickedListener(view -> {
                    TagView.this.remove(position);
                    if (mDeleteListener != null) {
                        mDeleteListener.onTagDeleted(position, tag);
                    }
                });
                //然后获取字体的宽度
                Paint textPaint = new Paint();
                textPaint.setTextSize(deletableView.getTextSize());
                float text2Width = textPaint.measureText(tag.deleteIcon);

                int deletableViewPadding = deletableView.getPaddingLeft() + deletableView.getPaddingRight();

                tagWidth += NumberUtil.add(text2Width , deletableViewPadding);
                LogUtil.error("text2Width", "" + text2Width);
                // deletableView Padding (left & right)
            } else {
                deletableView.setVisibility(HIDE);
            }
            DependentLayout.LayoutConfig tagParams = new DependentLayout.LayoutConfig(
                    ComponentContainer.LayoutConfig.MATCH_CONTENT,
                    ComponentContainer.LayoutConfig.MATCH_CONTENT
            );

            //tagParams.setMargins(0, 0, 0, 0);
            //add margin of each line
            tagParams.setMarginBottom(lineMargin);

            int intValue = tagMargin + ResolutionUtil.dpToPx(this.getContext(), Constants.LAYOUT_WIDTH_OFFSET);
            double doubleValue = NumberUtil.add(total,tagWidth);
            if (mWidth <= NumberUtil.add(doubleValue,intValue)) {
                //need to add in new line
                tagParams.addRule(DependentLayout.LayoutConfig.BELOW, index_bottom);
                // initialize total param (layout padding left & layout padding right)
                total = getPaddingLeft() + getPaddingRight();
                index_bottom = listIndex;
                index_header = listIndex;
                LogUtil.error("mWidth1", mWidth + "");
            } else {
                //no need to new line
                tagParams.addRule(DependentLayout.LayoutConfig.ALIGN_TOP, index_header);
                //not header of the line
                if (listIndex != index_header) {
                    tagParams.addRule(DependentLayout.LayoutConfig.RIGHT_OF, listIndex - 1);
                    tagParams.setMarginLeft(tagMargin);
                    //  total += tagMargin;
                    total = (float) NumberUtil.add(total,tagMargin);
                    if (tag_pre.tagTextSize < tag.tagTextSize) {
                        index_bottom = listIndex;
                    }
                }
            }
//            total += tagWidth;
            total = (float) NumberUtil.add(total,tagWidth);
            addComponent(tagLayout, tagParams);
            tag_pre = tag;
            listIndex++;
            LogUtil.error("mWidth2", total + "");
        }
    }

    /**
     * getSelector
     *
     * @param tag
     * @return Element
     */
    private Element getSelector(Tag tag) {
        if (tag.background != null) return tag.background;
        StateElement states = new StateElement();
        ShapeElement gd_normal = new ShapeElement();
        gd_normal.setRgbColor(MyUtils.getRgbColor(tag.layoutColor));
        gd_normal.setCornerRadius(tag.radius);
        if (tag.layoutBorderSize > 0) {
            gd_normal.setStroke(ResolutionUtil.dpToPx(getContext(), tag.layoutBorderSize), MyUtils.getRgbColor(tag.layoutBorderColor));
        }
        ShapeElement gd_press = new ShapeElement();
        gd_press.setRgbColor(MyUtils.getRgbColor(tag.layoutColorPress));
        gd_press.setCornerRadius(tag.radius);
        //选中的样式
        states.addState(new int[]{ComponentState.COMPONENT_STATE_PRESSED}, gd_press);
        //must add state_pressed first，or state_pressed will not take effect
        states.addState(new int[]{}, gd_normal);
        return states;
    }

    /**
     * addTag
     *
     * @param tag
     */
    public void addTag(Tag tag) {
        LogUtil.error(TAG, "[addTag]");
        mTags.add(tag);
        drawTags();
    }

    /**
     * addTags
     *
     * @param tags
     */
    public void addTags(String[] tags) {
        LogUtil.error(TAG, "[addTags]");
        if (tags == null || tags.length <= 0) return;
        for (String item : tags) {
            Tag tag = new Tag(item);
            mTags.add(tag);
        }
        drawTags();
    }

    /**
     * addTags
     *
     * @param tagList
     */
    public void addTags(List<Tag> tagList) {
        LogUtil.error(TAG, "[addTags]");
        if (tagList == null || tagList.size() <= 0) return;
        mTags.addAll(tagList);
        drawTags();
    }

    /**
     * getTags
     *
     * @return List
     */
    public List<Tag> getTags() {
        return mTags;
    }

    /**
     * remove
     *
     * @param position
     */
    public void remove(int position) {
        LogUtil.error(TAG, "[remove]position = " + position);
        mTags.remove(position);
        drawTags();
    }

    /**
     * removeAllTags
     */
    public void removeAllTags() {
        LogUtil.error(TAG, "[removeAllTags]");
        mTags.clear();
        drawTags();
    }

    /**
     * getLineMargin
     *
     * @return int
     */
    public int getLineMargin() {
        return lineMargin;
    }

    /**
     * setLineMargin
     *
     * @param lineMargin
     */
    public void setLineMargin(float lineMargin) {
        this.lineMargin = ResolutionUtil.dpToPx(getContext(), lineMargin);
    }

    /**
     * getTagMargin
     *
     * @return int
     */
    public int getTagMargin() {
        return tagMargin;
    }

    /**
     * setTagMargin
     *
     * @param tagMargin
     */
    public void setTagMargin(float tagMargin) {
        this.tagMargin = ResolutionUtil.dpToPx(getContext(), tagMargin);
    }

    /**
     * getTextPaddingLeft
     *
     * @return int
     */
    public int getTextPaddingLeft() {
        return textPaddingLeft;
    }

    /**
     * setTextPaddingLeft
     *
     * @param textPaddingLeft
     */
    public void setTextPaddingLeft(float textPaddingLeft) {
        this.textPaddingLeft = ResolutionUtil.dpToPx(getContext(), textPaddingLeft);
    }

    /**
     * getTextPaddingRight
     *
     * @return int
     */
    public int getTextPaddingRight() {
        return textPaddingRight;
    }

    /**
     * setTextPaddingRight
     *
     * @param textPaddingRight
     */
    public void setTextPaddingRight(float textPaddingRight) {
        this.textPaddingRight = ResolutionUtil.dpToPx(getContext(), textPaddingRight);
    }

    /**
     * getTextPaddingTop
     *
     * @return int
     */
    public int getTextPaddingTop() {
        return textPaddingTop;
    }

    /**
     * setTextPaddingTop
     *
     * @param textPaddingTop
     */
    public void setTextPaddingTop(float textPaddingTop) {
        this.textPaddingTop = ResolutionUtil.dpToPx(getContext(), textPaddingTop);
    }

    /**
     * getTexPaddingBottom
     *
     * @return int
     */
    public int getTexPaddingBottom() {
        return texPaddingBottom;
    }

    /**
     * setTexPaddingBottom
     *
     * @param texPaddingBottom
     */
    public void setTexPaddingBottom(float texPaddingBottom) {
        this.texPaddingBottom = ResolutionUtil.dpToPx(getContext(), texPaddingBottom);
    }

    /**
     * setOnTagClickListener
     *
     * @param clickListener
     */
    public void setOnTagClickListener(OnTagClickListener clickListener) {
        mClickListener = clickListener;
    }

    /**
     * setOnTagDeleteListener
     *
     * @param deleteListener
     */
    public void setOnTagDeleteListener(OnTagDeleteListener deleteListener) {
        mDeleteListener = deleteListener;
    }
}
